use crate::utils::file;
use crate::cmd_result::CmdResult;
use crate::service::Connection;
use serde_json::Value;

const DATA_FILE: &str = "connect.json";

pub struct ConnectService { json: String }

impl ConnectService {
    pub fn new() -> Self { Self { json: "".to_string() } }

    pub fn save(&mut self) -> anyhow::Result<CmdResult> {
        let mut o: Connection = serde_json::from_str(&self.json)?;
        let mut os: Vec<Connection> = Self::all()?;

        if o.id.is_none() {
            o.id = os.iter()
                .map(|x| x.id.unwrap_or(0))
                .max()
                .map(|x| x + 1);
            os.push(o.clone());
        } else if let Some(i) = os.iter().position(|x| x.id == o.id) {
            os[i] = o.clone();
        }

        if Self::write(&os).is_ok() {
            return CmdResult::yes(String::new(), serde_json::to_string(&o)?);
        }

        CmdResult::no(String::new())
    }

    pub fn delete(&self) -> anyhow::Result<CmdResult> {
        if let Some(id) = serde_json::from_str::<Value>(&self.json)?
            .get("json")
            .and_then(|x| x.as_u64())
            .and_then(|x| Some(x as u16)) {

            let lst: Vec<Connection> = Self::all()?.into_iter()
                .filter(|x| x.id != Some(id))
                .collect();

            if Self::write(&lst).is_ok() {
                return CmdResult::yes(String::new(), String::new());
            }
        }

        CmdResult::no(String::new())
    }

    pub fn get_all(&self) -> anyhow::Result<CmdResult> {
        let all = Self::all()?;
        CmdResult::yes(String::new(), serde_json::to_string(&all)?)
    }
}

impl ConnectService {
    pub fn json(json: String) -> Self {
        Self { json }
    }
    pub fn all() -> anyhow::Result<Vec<Connection>> {
        let mut vc = crate::CONNECTIONS.lock().unwrap().to_vec();
        if vc.len() == 0 {
            let s = file::read(DATA_FILE)?;
            vc = serde_json::from_str::<Vec<Connection>>(&s)?;
            crate::CONNECTIONS.lock().unwrap().extend_from_slice(&vc);
        }
        Ok(vc)
    }
    pub fn find_by_id(id: u16) -> Option<Connection> {
        if let Ok(vs) = Self::all() {
            return vs.into_iter().find(|x| x.id == Some(id))
        }
        
        None
    }
}

impl ConnectService {
    fn write(os: &Vec<Connection>) -> anyhow::Result<usize> {
        crate::CONNECTIONS.lock().unwrap().clear();
        crate::CONNECTIONS.lock().unwrap().extend_from_slice(os);
        file::write_from_t(DATA_FILE, os)
    }
}